package com.vmove.childtrain.common;

import android.content.Context;
import android.hardware.usb.UsbManager;
import android.widget.Toast;


import com.vmove.childtrain.utils.ByteUtil;
import com.vmove.childtrain.utils.LogUtils;
import com.vmove.childtrain.utils.UIUtils;

import java.nio.ByteBuffer;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import cn.wch.ch34xuartdriver.CH34xUARTDriver;


/**
 * @Description: 自定义ch341串口驱动管理类 单例模式
 */

public class CustomSerialDriver {

    private static CustomSerialDriver instance;
    private Listener mListener;
    CH34xUARTDriver mDriver ;
    private Context mContext;
    private static final String ACTION_USB_PERMISSION = "cn.wch.wchusbdriver.USB_PERMISSION";
    private boolean isOpen = false;
    private int BUFSIZ = 128;
    private final ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ);
    private final ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);

    private int baudRate=115200;
    private byte stopBit=1;
    private byte dataBit=8;
    private byte parity=0;
    private byte flowControl=0;

    private Queue<byte[]> writeQueue;
    private ReadThread mReadThread;
    private WriteThread mWriteThread;
    private int toastDoor=16;
    private int toastCount=0;

    public static CustomSerialDriver getInstance(CH34xUARTDriver driver) {
        if (null == instance) {
            synchronized (CustomSerialDriver.class){
                instance = new CustomSerialDriver(driver, AppContext.getInstance());
            }
        }
        return instance;
    }

    private CustomSerialDriver(CH34xUARTDriver driver, Context context) {
        this.mDriver = driver;
        this.mContext = context;
        mDriver = new CH34xUARTDriver(
                (UsbManager) context.getSystemService(Context.USB_SERVICE), context,
                ACTION_USB_PERMISSION);
        writeQueue = new ConcurrentLinkedQueue<>();
        //有些平板电脑会在息屏后关闭otg，所以初始化driver放在activity的onresume方法里
//        initDriver();
    }

    public void initDriver() {
        if (isConnect()){
            //已经连接了，无需再配置
            return;
        }
        if (null!=mReadThread){
            mReadThread.stopMe();
        }
        if (null!=mWriteThread){
            mWriteThread.stopMe();
        }
        int retval = mDriver.ResumeUsbPermission();
        if (retval==0){
            // ResumeUsbList方法用于枚举CH34X设备以及打开相关设备
            //这个函数包含了EnumerateDevice，OpenDevice 操作
            retval = mDriver.ResumeUsbList();
            if (retval == -1){
                Toast.makeText(mContext, "打开设备失败!", Toast.LENGTH_SHORT).show();
                mDriver.CloseDevice();
            } else if (retval == 0) {
                //打开设备成功
                if(mDriver.mDeviceConnection!=null) {
                    if (!mDriver.UartInit()) {//对串口设备进行初始化操作
                        Toast.makeText(mContext, "初始化设备失败!", Toast.LENGTH_SHORT).show();
                        return;
                    }
                    //配置设备
                    if (mDriver.SetConfig(baudRate, dataBit, stopBit, parity,//配置串口波特率，函数说明可参照编程手册
                            flowControl))
                    isOpen = true;
                    mReadThread = new ReadThread();
                    mReadThread.start();//开启读线程读取串口接收的数据
                    mWriteThread = new WriteThread();
                    mWriteThread.start();//开启写线程写入数据到串口
                }else{
                    UIUtils.showToastSafe("Open failed");
                }
            } else {
                //未授权
            }
        }
    }

    public String getDeviceStatus(){
        if (null==mDriver) return "未发现设备";
        if (mDriver.isConnected()){
            return "已连接";
        }else {
            return "未成功连接";
        }
    }

    public boolean isConnect(){
        if (null==mDriver)
            return false;
        return mDriver.isConnected() && isOpen;
    }

    private class ReadThread extends Thread {

        boolean isRead = true;

        public void stopMe() {
            isRead = false;
        }

        public void run() {
            byte[] buffer = new byte[BUFSIZ];
            while (true) {
                if (!isOpen) {
                    break;
                }
                if (!isRead)
                    break;
                int length = mDriver.ReadData(buffer, BUFSIZ);
                if (length > 0) {
                    byte[] data = new byte[length];
                    System.arraycopy(buffer, 0, data, 0, length);
//                    mReadBuffer.get(data, 0, length);
                    if (null != mListener) {
                        mListener.onNewData(data);
                    }
//                    mReadBuffer.clear();
                }
            }
        }
    }

    private class WriteThread extends Thread {

        boolean isWrite = true;

        public void stopMe() {
            isWrite = false;
        }

        public void run() {
            while (true) {
                if (!isOpen) {
                    break;
                }
                if (!isWrite)
                    break;
                if (!writeQueue.isEmpty()){
                    byte[] data = writeQueue.poll();
                    if (null!=data){
                        mDriver.WriteData(data, data.length);
                    }
                }
                try {
                    sleep(Constants.COMMAND_INTERVAL);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 关闭设备
     */
    public void closeSerial(){
        if (null!=mDriver){
            mDriver.CloseDevice();
            isOpen = false;
        }
    }

    public void writeData(byte[] data) {
        LogUtils.i("串口发送数据"+ ByteUtil.bytesToHexString(data, true));
        if (null != mDriver && mDriver.isConnected()) {
//            mDriver.WriteData(data, data.length);
            writeQueue.add(data);
        }else {
            if ((toastCount++%toastDoor) ==0)
                UIUtils.showToastSafe("接收器未正确连接");
        }
    }



    public interface Listener {
        public void onNewData(byte[] data);

        public void onRunError(Exception e);
    }

    public void setDataListener(Listener mListener) {
        this.mListener = mListener;
    }
}
